package com.example.filter;

import com.example.pojo.UrlLogBo;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Activate(group = {CommonConstants.CONSUMER})
public class TPMonitorFilter implements Filter, Runnable {
    private static final Logger logger = LoggerFactory.getLogger(TPMonitorFilter.class);

    private final Map<String, UrlLogBo> urlLogBo_POOL = new ConcurrentHashMap<>();

    private final float TP_90 = 0.9f;

    private final float TP_99 = 0.99f;

    public TPMonitorFilter() {
        //每隔5秒打印线程方法TP90、TP99的耗时情况
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(this, 5, 5, TimeUnit.SECONDS);
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long start = System.currentTimeMillis();
        URL url = invoker.getUrl();
        String methodName = invocation.getMethodName();
        UrlLogBo urlLogBo = urlLogBo_POOL.get(methodName);

        if(urlLogBo == null){
            urlLogBo = new UrlLogBo(methodName);
            urlLogBo_POOL.put(methodName, urlLogBo);
        }

        try {
            return invoker.invoke(invocation);
        } finally {
            long stop = System.currentTimeMillis();
            urlLogBo.putTime(stop-start);
        }
    }

    @Override
    public void run() {
        for (Map.Entry<String, UrlLogBo> urlUrlLogBoEntry : urlLogBo_POOL.entrySet()) {
            UrlLogBo logBo = urlUrlLogBoEntry.getValue();
            int numOfCall = logBo.getNumOfCall()+1;
            String methodName = logBo.getMethodName();
            List<Long> useTimeList = logBo.getUseTimeList();
            int size = useTimeList.size();
            if(size > 0){
                int pt_90 = Math.round(size * TP_90) - 1;
                int pt_99 = Math.round(size * TP_99) - 1;
                logger.info("{} TP90: {} ms  TP99: {} ms   list size:{}", methodName, useTimeList.get(pt_90), useTimeList.get(pt_99), size);
            }else{
                logger.info("{} 暂无请求", logBo.getMethodName());
            }

            if(numOfCall % 12 == 0){//1分钟后清空List
                logBo.cleanList();
                logger.info("方法 {} : 监听已满一分钟准备清空集合", methodName);
            }

            logBo.setNumOfCall(numOfCall);
        }
        System.out.println("=================================================================");
    }
}
